class_name GameMap
extends Node2D


@export var map_width: int = 300
@export var map_height: int = 300
@export var cell_size: int = 16
@export var reveal_radius_x: int = 10
@export var reveal_radius_y: int = 5

var ground_layers: Array[TileMapLayer]       # 9 个 TileMapLayer
var layer_offsets: Array[Vector2]          # 对应每个 layer 在全局格子坐标系的偏移
var level: Level

@onready var map_display: Sprite2D = $GameMapSprite
@onready var player_marker: Marker2D = $GameMapSprite/PlayerMarker

var explored: Array = []
var map_img: Image
var map_tex: ImageTexture

@onready var other_marker_parent: Marker2D = $GameMapSprite/OtherMarkerParent

var data: GameMapData


func init_by_data(d: GameMapData):
	self.data = d
	
	explored = data.explored
	if not explored:
		explored.resize(map_width)
		for x in range(map_width):
			explored[x] = []
			for y in range(map_height):
				explored[x].append(false)
	
	init_ground_layers()
			
	# 初始化贴图（全透明）
	map_img = Image.create(map_width, map_height, false, Image.FORMAT_RGBA8)
	map_img.fill(Color(0, 0, 0, 0.0))
	map_tex = ImageTexture.create_from_image(map_img)
	map_display.texture = map_tex
	
	init_map_texture()
	

func init_ground_layers():
	ground_layers = []
	layer_offsets = []
	
	for region in level.regions:
		var ground_tilemap_layer = region.get_ground_tilemap_layer()
		ground_layers.append(ground_tilemap_layer)
		
		var offset = Vector2(int(ground_tilemap_layer.global_position.x / cell_size), int(ground_tilemap_layer.global_position.y / cell_size)) 
		layer_offsets.append(offset)
		
		if region.exit_tilemap_layer_top.enabled:
			ground_layers.append(region.exit_tilemap_layer_top)
			offset = Vector2(int(region.exit_tilemap_layer_top.global_position.x / cell_size), int(region.exit_tilemap_layer_top.global_position.y / cell_size)) 
			layer_offsets.append(offset)
			
		if region.exit_tilemap_layer_right.enabled:
			ground_layers.append(region.exit_tilemap_layer_right)
			offset = Vector2(int(region.exit_tilemap_layer_right.global_position.x / cell_size), int(region.exit_tilemap_layer_right.global_position.y / cell_size)) 
			layer_offsets.append(offset)
		
		if region.exit_tilemap_layer_bottom.enabled:
			ground_layers.append(region.exit_tilemap_layer_bottom)
			offset = Vector2(int(region.exit_tilemap_layer_bottom.global_position.x / cell_size), int(region.exit_tilemap_layer_bottom.global_position.y / cell_size)) 
			layer_offsets.append(offset)
			
		if region.exit_tilemap_layer_left.enabled:
			ground_layers.append(region.exit_tilemap_layer_left)
			offset = Vector2(int(region.exit_tilemap_layer_left.global_position.x / cell_size), int(region.exit_tilemap_layer_left.global_position.y / cell_size)) 
			layer_offsets.append(offset)
	

func _process(delta: float) -> void:
	if not level.player:
		return

	var player_cell = get_player_cell(level.player.global_position)
	explore_around_player(player_cell, reveal_radius_x, reveal_radius_y)
	
	process_map_position()
	

func process_map_position():
	var player_map_pos = get_player_map_pos_center()
	var camera_center_position = level.get_camera_center_position_limit()
	map_display.global_position = camera_center_position - player_map_pos * map_display.scale
	player_marker.position = player_map_pos
	
	
func add_marker(id: String, level_pos: Vector2, texture_name: String, scale: float = 0.1):
	var marker_map_pos_center = get_map_pos_center_from_level_pos(level_pos)
	var inst = (ResourceManager.get_resource("map_marker") as PackedScene).instantiate() as Sprite2D
	inst.name = id
	inst.texture = ResourceManager.get_resource(texture_name)
	inst.scale = Vector2(scale, scale)
	other_marker_parent.add_child(inst)
	inst.position = marker_map_pos_center
	

func update_marker_pos(id: String, level_pos: Vector2):
	var target = get_marker(id)
	if target:
		var marker_map_pos_center = get_map_pos_center_from_level_pos(level_pos)
		target.position = marker_map_pos_center
		
	
func destroy_marker(id: String):
	var target = get_marker(id)
	if target:
		target.queue_free()
	

func get_marker(id: String):
	for index in range(other_marker_parent.get_child_count()):
		var marker =  other_marker_parent.get_child(index)
		if marker.name == id:
			return marker
	return null
	

func get_player_map_pos_center():
	var map_x = (level.player.global_position.x / 4800.0) * 300 - 150
	var map_y = (level.player.global_position.y / 4800.0) * 300 - 150
	return Vector2(map_x, map_y)
	

func get_map_pos_center_from_level_pos(level_pos: Vector2):
	var map_x = (level_pos.x / 4800.0) * 300 - 150
	var map_y = (level_pos.y / 4800.0) * 300 - 150
	return Vector2(map_x, map_y)
	
	
func get_player_cell(world_pos: Vector2) -> Vector2i:
	return Vector2i(int(world_pos.x / cell_size), int(world_pos.y / cell_size))


func init_map_texture():
	for x in range(map_width):
		for y in range(map_height):
			if explored[x][y]:
				var is_wall: bool = false
				
				for i in range(ground_layers.size()):
					var layer = ground_layers[i]
					var offset = layer_offsets[i]
					var local_pos = Vector2i(x - offset.x, y - offset.y)

					if layer.get_cell_source_id(local_pos) != -1:   # Godot4: 使用 has_cell 或 get_cell_source_id
						is_wall = true
						break

				if is_wall:
					map_img.set_pixel(x, y, Color(0.57, 0.699, 1.0, 0.314)) # 已探索墙体
				else:
					map_img.set_pixel(x, y, Color(0.102, 0.142, 0.3, 0.314)) # 已探索可走

	map_tex.update(map_img)


func explore_around_player(center: Vector2i, radius_x: int, radius_y: int) -> void:
	var px = center.x
	var py = center.y
	for x in range(px - radius_x, px + radius_x + 1):
		for y in range(py - radius_y - 1, py + radius_y + 1):
			if x < 0 or y < 0 or x >= map_width or y >= map_height:
				continue
			if explored[x][y]:
				continue

			explored[x][y] = true
			var is_wall := false

			# 遍历所有 TileMapLayer
			for i in range(ground_layers.size()):
				var layer = ground_layers[i]
				var offset = layer_offsets[i]
				var local_pos = Vector2i(x - offset.x, y - offset.y)

				if layer.get_cell_source_id(local_pos) != -1:   # Godot4: 使用 has_cell 或 get_cell_source_id
					is_wall = true
					break

			if is_wall:
				map_img.set_pixel(x, y, Color(0.57, 0.699, 1.0, 0.314)) # 已探索墙体
			else:
				map_img.set_pixel(x, y, Color(0.102, 0.142, 0.3, 0.314)) # 已探索可走

	map_tex.update(map_img)
